package com.online.server.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.online.server.enums.MessageEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
@Service
@ServerEndpoint("/api/websocket/{sid}/{key}")
public class WebSocketServer {

    //存放每个客户端对应的MyWebSocket对象
    private static ConcurrentHashMap<String, List<WebSocketServer>> webSocketSet = new ConcurrentHashMap<>();
    //文档分段锁
    private static ConcurrentHashMap<String, Object> maplock = new ConcurrentHashMap<>();

    private Session session;

    //接收sid
    private String sid = "";
    private String key = "";

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid, @PathParam("key") String key) {
        this.session = session;
        this.sid = sid;
        this.key = key;
        Object object = null;
        if (!maplock.contains(sid)) {
            object = new Object();
            maplock.put(sid, object);
        } else {
            object = maplock.get(sid);
        }
        synchronized (object) {
            List<WebSocketServer> webSocketServers = webSocketSet.get(sid);
            this.getmessage(webSocketServers);//获取最新的消息
            if (CollectionUtils.isEmpty(webSocketServers)) {
                webSocketServers = new ArrayList<>();
            }
            if (!webSocketServers.contains(this)) {
                webSocketServers.add(this);
            }
            webSocketSet.put(sid, webSocketServers);

        }
        log.info("有新窗口开始监听:sid为" + sid + "key为" + key + ",当前在线人数为:" + getOnlineCount());

    }

    public void getmessage( List<WebSocketServer>webSocketServers)  {
        Map data=new HashMap();
        data.put("type", MessageEnum.GET_MESSAGE.type);
        data.put("to",this.key);
        data.put("content","");
        if(!CollectionUtils.isEmpty(webSocketServers)){
            int i=0;
            while(i<webSocketServers.size()) {
                try {
                    if( webSocketServers.get(i).session.isOpen()) {
                        webSocketServers.get(i).sendMessage(JSON.toJSONString(data));
                        break;
                    }else{
                        webSocketServers.get(i).onClose();
                        i++;
                    }
                } catch (IOException e) {
                    i++;
                    throw new RuntimeException(e);
                }
            }
            if(i>=webSocketServers.size()){//全部发送失败
                try {
                    if(this.session.isOpen()) {
                        this.sendMessage(JSON.toJSONString(data));
                    }else{
                        this.onClose();
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

        }else{
            try {
                if(this.session.isOpen()) {
                    this.sendMessage(JSON.toJSONString(data));
                }else{
                    this.onClose();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        Object object = null;
        if (!maplock.contains(sid)) {
            object = new Object();
            maplock.put(sid, object);
        } else {
            object = maplock.get(sid);
        }
        synchronized (object) {
            try {
                List<WebSocketServer> webSocketServers = webSocketSet.get(sid);
                Iterator<WebSocketServer> iterator = webSocketServers.iterator();
                while (iterator.hasNext()) {
                    WebSocketServer next = iterator.next();
                    if (next.getKey().equals(this.key)) {
                        iterator.remove();
                    }
                }
                webSocketSet.put(sid, webSocketServers);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
        log.info("释放的sid为：{},key为{}", sid, this.key);
        log.info("有一连接关闭！sid为：{},key为{}当前在线人数为{}", sid, key, getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @ Param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        Object object = null;
        if (!maplock.contains(sid)) {
            object = new Object();
            maplock.put(sid, object);
        } else {
            object = maplock.get(sid);
        }
        synchronized (object) {
            log.info("收到来自sid为" + sid + "key为" + key + "的信息:" + message);
            try {
                JSONObject m = JSON.parseObject(message);
                List<WebSocketServer> webSocketServers = webSocketSet.get(sid);
                if (MessageEnum.GET_MESSAGE.type.equals(m.get("type"))) {//拉去的最新消息
                    for (WebSocketServer item : webSocketServers) {
                        try {
                            if (item.getKey().equals(m.get("to"))) {//发送给指定人
                                if (item.session.isOpen()) {
                                    item.sendMessage(message);
                                } else {
                                    item.onClose();
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                            item.onClose();
                        }

                    }
                } else if (MessageEnum.UPD_MESSAGE.type.equals(m.get("type"))) {
                    for (WebSocketServer item : webSocketServers) {
                        try {
                            if (!item.getKey().equals(this.key)) {//自己不发送
                                if (item.session.isOpen()) {
                                    item.sendMessage(message);
                                } else {
                                    item.onClose();
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                            item.onClose();
                        }
                    }
                } else {
                    log.warn("暂不支持此类型的消息{}", message);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }


    }

    /**
     * @ Param session
     * @ Param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        this.onClose();
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public int getOnlineCount() {
        return webSocketSet.get(sid).size();
    }


    public static ConcurrentHashMap<String, List<WebSocketServer>> getWebSocketSet() {
        return webSocketSet;
    }

}
